iT邦幫忙

第 12 屆 iThome 鐵人賽

0

記錄學習內容。看網路上大大們的文章和影片,做些紀錄。
以下內容大多來自網路上大大們的文章。
還不了解,內容可能有錯誤。

C# beginners :- Assembly , EXE and DLL

https://www.youtube.com/watch?v=lx2tSY4joDg&ab_channel=.NETInterviewPreparationvideos

C#按執行後 ,會在bin裡的debug或realease產生這些檔案:

https://ithelp.ithome.com.tw/upload/images/20201005/20111994911t779etS.png

只需要Exe檔就可以執行了,其他兩個不需要。

看作業系統:

【小黑馬作業系統教室統整】自編超齊全的「作業系統」科目學習整理
https://ithelp.ithome.com.tw/articles/10229671?sc=rss.qu
【小黑馬作業系統教室】(9) (Ch8) 記憶體管理,OS決定使用者寫程式的變數存在記憶體的哪個位置
https://ithelp.ithome.com.tw/articles/10229489
【小黑馬作業系統考古】範圍: 恐龍書第八章~第九章
https://ithelp.ithome.com.tw/articles/10229522

以下內容來自大大的文章:

當一個電腦使用者寫了一支程式,
要執行這支程式大致上有三個步驟:
1 由compiler編譯程式 (註:將人類可以看懂的程式碼轉為電腦看的懂的0101語言)
2 將程式讀進記憶體(memory)中
3 執行程式

一支程式裡會有許多變數,
變數放在記憶體的位置稱為變數的地址。

決定變數地址的行為稱為綁定(address binding),
那麼可以綁定變數地址的時機也就是上述說的三個時間點了:

  1. Compile time (compiler編譯程式時即決定地址)
  2. Load time (將程式讀進記憶體(memory)時才決定地址)
  3. Execution time (程式的時間動態決定地址)

開啟exe檔後,在用到dll套件的func時,exe檔會去 import .dll套件。
所以.dll套件的變數的地址 就是程式 Execution time 時決定的。

Compile time 時決定地址 想成:
真實地址直接寫死在程式裡, 之後製作exe檔 。

Load time (將程式讀進記憶體(memory)時才決定地址) 想成:
( 程式讀進記憶體後 ,開始為每個變數分配 真實地址  )

Execution time 想成:
Import  .dll 

// 以上是自己覺得好記的方法 ,內容應該錯誤。

看一下dll的維基 :

https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93
動態連結函式庫(Dynamic-link library,縮寫為DLL)

當執行檔呼叫到DLL檔內的函式(方法) 時,
Windows作業系統才會把DLL檔載入記憶體內,
DLL檔本身的結構就是可執行檔(exe),
當程式有需求時函式才進行連結。
透過動態連結方式,記憶體浪費的情形將可大幅降低。

維基寫得很詳盡 ,不過看不懂。

C#要讀寫資料 ,可以用.ini檔案的方式:

.Net 存取 INI Files
https://iammic.pixnet.net/blog/post/19789686-.net-%E5%AD%98%E5%8F%96-ini-files

會發現有這個東西
[DllImport("kernel32")]

改成這樣:
[DllImport("kernel321111")]

程式執行後,用到func時 ,才會發生錯誤:

System.DllNotFoundException: '無法載入 DLL 'kernel321111': 找不到指定的模組。 (發生例外狀況於 HRESULT: 0x8007007E)'

接著繼續看作業系統

OS - Ch8 記憶體管理 Memory Management
https://mropengate.blogspot.com/2015/01/operating-system-ch8-memory-management.html

重複使用其他程式碼 有 三種方法

(像是dll 就是 重複使用的程式碼)

(這邊跟前面的 綁定變數地址的時機 ,有點混亂)

(總之 ,link或load代表 什麼時候 加入 另一隻程式(library)
,加入 另一隻程式 代不代表 另一隻程式的記憶體位址 也是這時候加入的 ? 我不知道,先理解到這 。)

Static link

Compile 時 library 就加入程式碼。
感覺好像 是指 在 變成一堆0101010 exe檔 前 , 套件和主程式 已經 合而為一了。
但好像不代表 : 套件的變數地址 ,在compile時決定 。
因為只是 套件和主程式 合而為一 ,還沒有要 決定他們的變數地址吧?

Dynamic linking (Share library)

Dynamic linking是對於在很多支process之間,讓它們link相同的library,就不必每支process都存一個。

[DllImport("kernel32")] 就算這個嗎?

需要 OS 支持,不同 OS 有不同的稱呼。
Windows .dll (Dynamic Linking Libraries)
Linux .so (Shared Object)。

Dynamic loading

Dynamic loading是對一支process而言,在需要使用到函數時才讀進CPU中。
讓 programmer 在程式執行的過程中,動態決定要載入的libraries。

If (我需要dll)
載入dll 。

[DllImport("kernel32")] 算不算 Dynamic loading ?
感覺算 ,因為 用到 才會載入

加入參考是?

https://ithelp.ithome.com.tw/upload/images/20201005/20111994SAZk4T032R.png

觀察使用加入參考 的 dll 。

在.NET Core下 ,發現 刪掉 dll檔後 ,exe檔就不能開了 ,就算程式沒用到該dll檔!!!

.NET Core 有一個檔案 是 專案名稱.csproj

裡面有這樣的內容 :

  <ItemGroup>
    <Reference Include="itextsharp">
      <HintPath>..\..\..itextsharp.dll</HintPath>
    </Reference>
    
    <Reference Include="Newtonsoft.Json">
      <HintPath>Dll\Newtonsoft.Json.dll</HintPath>
    </Reference>
  </ItemGroup>

雖然 dll檔 在不同路徑 ,但是執行後

在 bin\Debug\netcoreapp3.1\
會新增同樣的dll檔案,跟exe檔放在同個目錄!!!

而且刪掉dll檔後,exe就開不起來了。

所以 這個方法 ,會在程式 編譯成exe時 ,把套件 複製一分到 同樣目錄下 。
exe檔 開不起來是因為 ,一開始 開exe 檔 ,程式就會自己 載入 套件 ? 發現目錄下沒有套件,就錯誤了?

程式加入dll的方法

Loading DLLs at runtime in C#
https://stackoverflow.com/questions/18362368/loading-dlls-at-runtime-in-c-sharp

var DLL = Assembly.LoadFile(@"C:\Users\test\Desktop\itextsharp.dll");

var class1Type = DLL.GetType("iTextSharp.text.pdf.parser.LocationTextExtractionStrategy");

dynamic c = Activator.CreateInstance(class1Type);

c.StartsWithSpace(@"Hello");

itextsharp
https://github.com/itext/itextsharp/blob/develop/src/core/iTextSharp/text/pdf/parser/LocationTextExtractionStrategy.cs

iTextSharp.text.pdf.parser.LocationTextExtractionStrategy 代表
https://ithelp.ithome.com.tw/upload/images/20201006/20111994gZo2zStn3x.png

https://ithelp.ithome.com.tw/upload/images/20201006/20111994GbMcCEPBd5.png

c.StartsWithSpace(@"Hello");
表示 StartsWithSpace 方法 ,參數 是"Hello"
https://ithelp.ithome.com.tw/upload/images/20201006/20111994vdWG57E8yC.png

因為這個方法 是 private 所以會有這個錯誤:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''iTextSharp.text.pdf.parser.LocationTextExtractionStrategy.StartsWithSpace(string)' is inaccessible due to its protection level'

換一個方法:
https://ithelp.ithome.com.tw/upload/images/20201006/20111994JCfWKIW0C7.png

c.StartsWithSpace(@"Hello"); 改成 c.BeginTextBlock();

總之程式可以正常執行了 。
目前猜測這樣寫 ,只會載一份而已

            for (int i = 0; i <= 100; i++)
            {
                Assembly.LoadFile(@"C:\Users\test\Desktop\itextsharp.dll");
            }

因為這個只出現一次:

TestDLLLoad.exe' (CLR v4.0.30319: TestDLLLoad.exe): 已載入 'C:\Users\test\Desktop\itextsharp.dll'。建置的模組沒有符號。

看這部教學:

計算機組織 Chapter 2.11 Linking object files - 朱宗賢老師
https://www.youtube.com/watch?v=uTIjdnMstBc&list=PLylnxZnYW9LbVL5HnYwo7VLmlkhM7lTey&index=18&ab_channel=edwardchu

講到 把多個檔案 (assembler) 經過 linker 後 變 exe檔 。

看不太懂 ,了解了一些:

1

load 和 save 指令 的機器語言 ,後面的16位的bit ,是 有號數(正數或負數)

2

多個檔案 (assembler) 在還沒合併前 ,位址都寫0 之類的 。
合併成exe 後 ,才會把 記憶體位址 補上 。

但是這個記憶體位址 , 是邏輯位址 ,還是 真實位址 ? 我不知道 。

3

關於一個程式 ,在記憶體中的配置 ?
OS - Ch3 行程 Process
https://mropengate.blogspot.com/2015/01/operating-system-ch3-processes.html

C 語言程式的記憶體配置概念教學
https://blog.gtwang.org/programming/memory-layout-of-c-program/

以下內容來自大大的文章:

stack : 存放函數的參數、區域變數等。
每一次的函數呼叫就會在堆疊區段建立一個 stack frame,儲存該次呼叫的所有變數與狀態,這樣一來同一個函數重複被呼叫時就會有不同的 stack frame,不會互相干擾,遞迴函數就是透過這樣的機制來執行的。

heap : 一般由程式設計師分配釋放,執行時才會知道配置大小,如 malloc/new 和 free/delete。
C 語言的 malloc 以及 C++ 的 new 所建立的變數都是儲存於此。

BSS :全域變數(global variables)以及靜態變數(static variables),但是沒有初始化(沒有給值) 。
這些變數在程式執行之前 會被系統初始化為 0 或是 null。

data : 全域變數(global variables)以及靜態變數(static variables),有給值,像是 static int a=123

text : 文字區段(text segment)也稱為程式碼區段(code segment),這裡存放的是可執行的 CPU 指令(instructions)、常數(像是123456)。

所以程式部分(sw lw jal 指令) 屬於text/code 。

初始化就是有給值,未初始化話就是沒給值

int a=0;   //data 區塊 因為 global 和 給值
char *p1;  // BSS 區塊  因為  global 和沒給值
double global[30];  //  BSS 區塊  因為  global 和沒給值

 main(){
    int b;             // stack 區塊 ,因為區域變數
    int c = 1;             // stack 區塊 ,因為區域變數
    
    static int z;      // bss區塊,因為 有static 和 沒給值
    static int c=0;   // data區塊 ,因為static和有給值
    
    char *p3="123456"; // 123456\0 在text區塊, 因為123456算是常量。
    //p3 在stack 區塊 ,因為區域變數 。
    
    p2 = (char*)malloc(20);  //heap 區塊 ,因為malloc
    
    strcpy(p1,"123456");  
    //123456\0 在常量區,編譯器可能會將它與 p3 中的 123456\0 優化成一個地方。
    
}

還不了解,內容可能有錯誤。


上一篇
C#,UDP、TCP
下一篇
排序(sort)筆記
系列文
學習筆記46
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言